package jj.rmirm.manager;

import java.rmi.AccessException;
import java.rmi.NoSuchObjectException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import jj.rmirm.interfaces.LogDisplayObservable;
import jj.rmirm.interfaces.LogDisplayObserver;

public class RMIManager implements LogDisplayObservable {

	private RMIManager() {
	}
	
	public static RMIManager getManager() {
		return manager;
	}
	
	@Override
	public void registerObserver(LogDisplayObserver ldo) {
		obserwator = ldo;
	}
	
	@Override
	public void informObservers(String message) {
		obserwator.display(message);
	}

	public void setServerParams(String address, int port) {
		this.serverAddr = address;
		this.serverPort = port;
		this.informObservers(READY);
	}
	
	public boolean startLocalRegistry() {
		boolean noErrors = true;
		
		try {
			rmiRegistry = LocateRegistry.createRegistry(serverPort);
			this.isRunning = true;
			this.informObservers(CREATE_REGISTRY_OK + serverPort);
		} catch (RemoteException e) {
			noErrors = false;
			this.informObservers(CREATE_REGISTRY_ERR + serverPort);
		}
		
		return noErrors;
	}
	
	public boolean stopLocalRegistry() {
		boolean noErrors = true;
		
		try {
			UnicastRemoteObject.unexportObject(rmiRegistry, true);
			this.informObservers(REGISTRY_STOPPED_OK);
		} catch (NoSuchObjectException e) {
			noErrors = false;
			this.informObservers(REGISTRY_STOPPED_ERR);
		}
		this.isRunning = false;
		
		return noErrors;
	}
	
	public boolean isRegistryRunning() {
		return isRunning;
	}
	
	public String[] listObjects() {
		String result[] = null;
		
		try {
			Registry registry = LocateRegistry.getRegistry(serverAddr, serverPort);
			this.objectList = registry.list();
			result = this.objectList;
			this.informObservers("Found " + result.length + " objects");

		} catch (AccessException e) {
			this.informObservers(BLOCKED_BY_REMOTE_REG + serverAddr + ":" + serverPort);
			result = null;
		} catch (RemoteException e) {
			this.informObservers(CANNOT_CONNECT + serverAddr + ":" + serverPort);
			result = null;
		}	
		
		return result;
	}
	
	public boolean unbindObject(String name) {
		boolean noErrors = true;
		
		try {
			Registry registry = LocateRegistry.getRegistry(serverAddr, serverPort);
			registry.unbind(name);
			this.informObservers("Object " + name + SUCCESFULLY_UNBOUND);
			
		} catch (AccessException e) {
			noErrors = false;
			this.informObservers(BLOCKED_BY_REMOTE_REG + serverAddr + ":" + serverPort);
		} catch (RemoteException e) {
			noErrors = false;
			this.informObservers(CANNOT_CONNECT + serverAddr + ":" + serverPort);
		} catch (NotBoundException e) {
			noErrors = false;
			this.informObservers(UNBIND_ERROR + name);
		}
		
		return noErrors;
	}
	
	private static RMIManager manager = new RMIManager();
	
	private LogDisplayObserver obserwator;
	private Registry rmiRegistry;
	private int serverPort;
	private String serverAddr;
	private boolean isRunning;
	private String objectList[] = null;
	
	private static final String READY = "Ready";
	private static final String CREATE_REGISTRY_OK = "Local RMI registry is running on port ";
	private static final String CREATE_REGISTRY_ERR = "Cannot run local RMI registry on port: ";
	private static final String REGISTRY_STOPPED_OK = "Registy stopped";
	private static final String REGISTRY_STOPPED_ERR = "Error while stopping local registry. Already stopped?";
	private static final String BLOCKED_BY_REMOTE_REG = "Blocked by remote registry: ";
	private static final String CANNOT_CONNECT = "Cannot connect ro RMI registry: ";
	private static final String SUCCESFULLY_UNBOUND = " succesfully unbound";
	private static final String UNBIND_ERROR = "There is no such object: ";
}
